/*
 * Copyright (C) 2016 JetRadar
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jetradarmobile.snowfall;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.VectorElement;
import ohos.agp.render.Canvas;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.image.PixelMap;

import java.util.ArrayList;
import java.util.logging.Logger;

public class SnowfallView extends ComponentContainer implements
        Component.BindStateChangedListener,
        Component.DrawTask,
        ComponentContainer.ArrangeListener {
    private Integer snowflakesNum;
    private PixelMap snowflakeImage;
    private Integer snowflakeAlphaMin;
    private Integer snowflakeAlphaMax;
    private Integer snowflakeAngleMax;
    private Integer snowflakeSizeMinInPx;
    private Integer snowflakeSizeMaxInPx;
    private Integer snowflakeSpeedMin;
    private Integer snowflakeSpeedMax;
    private Boolean snowflakesFadingEnabled;
    private Boolean snowflakesAlreadyFalling;
    private UpdateSnowflakesThread updateSnowflakesThread;
    private ArrayList<Snowflake> snowflakes = null;
    private boolean haveAtLeastOneVisibleSnowflake;

    /**
     * 使用new方式调用构造方式
     *
     * @param context
     */
    public SnowfallView(Context context) {
        super(context);
        init(context, null);
    }

    /**
     * 在布局中引用调用的构造方式
     *
     * @param context
     * @param attrSet
     */
    public SnowfallView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context, attrSet);
    }

    /**
     * 在布局设置style中引用调用的构造方式
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public SnowfallView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context, attrSet);
    }

    private void init(Context context, AttrSet attrSet) {
        setBindStateChangedListener(this);
        setLayoutRefreshedListener(this::onComponentBoundToWindow);
        addDrawTask(this::onDraw);
        setArrangeListener(this::onArrange);
        snowflakesNum = attrSet.getAttr("snowflakesNum").get().getIntegerValue();
        Element imageValue = attrSet.getAttr("snowflakeImage").get().getElement();
        snowflakeImage = toPixelMap(imageValue);
        snowflakeAlphaMin = attrSet.getAttr("snowflakeAlphaMin").get().getIntegerValue();
        snowflakeAlphaMax = attrSet.getAttr("snowflakeAlphaMax").get().getIntegerValue();
        snowflakeAngleMax = attrSet.getAttr("snowflakeAngleMax").get().getIntegerValue();
        snowflakeSizeMinInPx = attrSet.getAttr("snowflakeSizeMin").get().getDimensionValue();
        snowflakeSizeMaxInPx = attrSet.getAttr("snowflakeSizeMax").get().getDimensionValue();
        snowflakeSpeedMin = attrSet.getAttr("snowflakeSpeedMin").get().getIntegerValue();
        snowflakeSpeedMax = attrSet.getAttr("snowflakeSpeedMax").get().getIntegerValue();
        snowflakesFadingEnabled = attrSet.getAttr("snowflakesFadingEnabled").get().getBoolValue();
        snowflakesAlreadyFalling = attrSet.getAttr("snowflakesAlreadyFalling").get().getBoolValue();

        // 硬件加速缺失;
    }

    private PixelMap toPixelMap(Element imageValue) {
        if (imageValue instanceof PixelMapElement) {
            return ((PixelMapElement) imageValue).getPixelMap();
        } else if (imageValue instanceof VectorElement) {
            Logger.getLogger("SnowfallView").fine("VectorElement");
        } else {
            throw new IllegalArgumentException("Unsupported drawable type");
        }
        return null;
    }

    @Override
    public void onComponentBoundToWindow(Component component) {
        if (updateSnowflakesThread == null) {
            updateSnowflakesThread = new UpdateSnowflakesThread(EventRunner.create());
        }
        // false
        if (getVisibility() == Component.HIDE) {
            for (Snowflake snowflake : snowflakes) {
                snowflake.reset(null);
            }
        }
        if (snowflakes == null) {
            snowflakes = createSnowflakes();
        }
    }

    @Override
    public void onComponentUnboundFromWindow(Component component) {
    }

    @Override
    public boolean onArrange(int i, int i1, int i2, int i3) {
        return true;
    }

    private ArrayList<Snowflake> createSnowflakes() {
        Randomizer randomizer = new Randomizer();
        Snowflake.Params snowflakeParams = new Snowflake.Params(
                getWidth(),
                getHeight(),
                snowflakeImage,
                snowflakeAlphaMin,
                snowflakeAlphaMax,
                snowflakeAngleMax,
                snowflakeSizeMinInPx,
                snowflakeSizeMaxInPx,
                snowflakeSpeedMin,
                snowflakeSpeedMax,
                snowflakesFadingEnabled,
                snowflakesAlreadyFalling);
        ArrayList<Snowflake> snowflakes = new ArrayList<>(snowflakesNum);
        for (int i = 0; i < snowflakesNum; i++) {
            snowflakes.add(new Snowflake(randomizer, snowflakeParams));
        }
        return snowflakes;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        boolean haveAtLeastOneVisibleSnowflake = false;
        if (snowflakes != null) {
            for (Snowflake snowflake : snowflakes) {
                if (snowflake.isStillFalling()) {
                    haveAtLeastOneVisibleSnowflake = true;
                    snowflake.draw(canvas);
                }
            }
        }

        // false
        if (haveAtLeastOneVisibleSnowflake) {
            // 线程更新
            updateSnowflakes();
        } else {
            setVisibility(Component.HIDE);
        }

        if (snowflakes != null) {
            for (Snowflake snowflake : snowflakes) {
                if (snowflake.isStillFalling()) {
                    snowflake.draw(canvas);
                }
            }
            updateSnowflakes();
        } else {
            setVisibility(Component.HIDE);
        }
    }

    private void updateSnowflakes() {
        haveAtLeastOneVisibleSnowflake = false;
        ArrayList<Snowflake> localSnowflakes;
        if (snowflakes != null) {
            localSnowflakes = snowflakes;
        } else {
            return;
        }
        for (Snowflake snowflake : localSnowflakes) {
            if (snowflake.isStillFalling()) {
                haveAtLeastOneVisibleSnowflake = true;
                snowflake.update();
            }
        }

        if (haveAtLeastOneVisibleSnowflake) {
            updateSnowflakesThread.postTask(new Runnable() {
                @Override
                public void run() {
                    getContext().getMainTaskDispatcher().syncDispatch(() -> {
                        // 更新UI的操作
                        invalidate();
                    });
                }
            });
        }
    }

    private class UpdateSnowflakesThread extends EventHandler {
        UpdateSnowflakesThread(EventRunner runner) throws IllegalArgumentException {
            super(runner);
        }
    }
}
